import util from '@ohos.util';

// useful stuff
export const inherits = function (cls, superCtor, statics, prototype) {
    // eslint-disable-next-line no-underscore-dangle
    cls.super_ = superCtor;

    if (!prototype) {
        prototype = statics;
        statics = null;
    }

    if (statics) {
        Object.keys(statics).forEach(i => {
            Object.defineProperty(cls, i, Object.getOwnPropertyDescriptor(statics, i));
        });
    }

    const properties = {
        constructor: {
            value: cls,
            enumerable: false,
            writable: false,
            configurable: true,
        },
    };
    if (prototype) {
        Object.keys(prototype).forEach(i => {
            properties[i] = Object.getOwnPropertyDescriptor(prototype, i);
        });
    }

    cls.prototype = Object.create(superCtor.prototype, properties);
};

export const nop = () => {
};
// eslint-disable-next-line no-control-regex
const xmlDecodeRegex = /[<>&'"\x7F\x00-\x08\x0B-\x0C\x0E-\x1F]/;

export const promiseImmediate = (value) => {
    return new Promise(resolve => {
        if (global.setImmediate) {
            setImmediate(() => {
                resolve(value);
            });
        } else {
            // poorman's setImmediate - must wait at least 1ms
            setTimeout(() => {
                resolve(value);
            }, 1);
        }
    });
};

export const dateToExcel = (d, date1904) => {
    // eslint-disable-next-line no-mixed-operators
    return 25569 + d.getTime() / (24 * 3600 * 1000) - (date1904 ? 1462 : 0);
};

export const excelToDate = (v, date1904) => {
    // eslint-disable-next-line no-mixed-operators
    const millisecondSinceEpoch = Math.round((v - 25569 + (date1904 ? 1462 : 0)) * 24 * 3600 * 1000);
    return new Date(millisecondSinceEpoch);
};

export const parsePath = (filepath) => {
    const last = filepath.lastIndexOf('/');
    return {
        path: filepath.substring(0, last),
        name: filepath.substring(last + 1),
    };
};

export const getRelsPath = (filepath) => {
    const path = parsePath(filepath);
    return `${path.path}/_rels/${path.name}.rels`;
};

export const xmlEncode = (text) => {
    const regexResult = xmlDecodeRegex.exec(text);
    if (!regexResult) {
        return text;
    }

    let result = '';
    let escape = '';
    let lastIndex = 0;
    let i = regexResult.index;
    for (; i < text.length; i++) {
        const charCode = text.charCodeAt(i);
        switch (charCode) {
            case 34: // "
                escape = '&quot;';
                break;
            case 38: // &
                escape = '&amp;';
                break;
            case 39: // '
                escape = '&apos;';
                break;
            case 60: // <
                escape = '&lt;';
                break;
            case 62: // >
                escape = '&gt;';
                break;
            case 127:
                escape = '';
                break;
            default: {
                if (charCode <= 31 && (charCode <= 8 || (charCode >= 11 && charCode !== 13))) {
                    escape = '';
                    break;
                }
                continue;
            }
        }
        if (lastIndex !== i) {
            result += text.substring(lastIndex, i);
        }
        lastIndex = i + 1;
        if (escape) {
            result += escape;
        }
    }
    if (lastIndex !== i) {
        return result + text.substring(lastIndex, i);
    }
    return result;
};

export const xmlDecode = (text) => {
    return text.replace(/&([a-z]*);/g, c => {
        switch (c) {
            case '&lt;':
                return '<';
            case '&gt;':
                return '>';
            case '&amp;':
                return '&';
            case '&apos;':
                return '\'';
            case '&quot;':
                return '"';
            default:
                return c;
        }
    });
};

export const validInt = (value) => {
    const i = parseInt(value, 10);
    return !Number.isNaN(i) ? i : 0;
};

export const isDateFmt = (fmt) => {
    if (!fmt) {
        return false;
    }

    // must remove all chars inside quotes and []
    fmt = fmt.replace(/\[[^\]]*]/g, '');
    fmt = fmt.replace(/"[^"]*"/g, '');
    // then check for date formatting chars
    const result = fmt.match(/[ymdhMsb]+/) !== null;
    return result;
};


export const toIsoDateString = (dt) => {
    return dt.toIsoString().subsstr(0, 10);
};

export const parseBoolean = (value) => {
    return value === true || value === 'true' || value === 1 || value === '1';
};

//生成器函数需要改造
export const range = (start, stop, step = 1) => {
    const compareOrder = step > 0 ? (a, b) => a < b : (a, b) => a > b;
    for (let value = start; compareOrder(value, stop); value += step) {
        return value;
    }
};

export const toSortedArray = (values) => {
    const result = Array.from(values);

    // Note: per default, `Array.prototype.sort()` converts values
    // to strings when comparing. Here, if we have numbers, we use
    // numeric sort.
    if (result.every(item => Number.isFinite(item))) {
        const compareNumbers = (a, b) => a - b;
        return result.sort(compareNumbers);
    }

    return result.sort();
};

export const objectFromProps = (props, value = null) => {
    // *Note*: Using `reduce` as `Object.fromEntries` requires Node 12+;
    // ExcelJs is >=8.3.0 (as of 2023-10-08).
    return props.reduce((result, property) => {
        result[property] = value;
        return result;
    }, {});
};

export const stringToArrayBuffer = (str) => {
    let textEncoder = new util.TextEncoder();
    let uint8Array = new Uint8Array(textEncoder.encodeInto(str).length);
    textEncoder.encodeIntoUint8Array(str, uint8Array);
    return uint8Array.buffer;
};

export const arrayBufferToString = (arrayBuffer, encoding = 'utf-8') => {
    let textDecoder = util.TextDecoder.create(encoding)
    let str = textDecoder.decodeToString(new Uint8Array(arrayBuffer))
    return str
};

